package org.example;

/**
 * @Author 李荣
 * @Date 2025/2/19
 * @Description
 */
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.universe.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;

public class Main3D {
    private static final int MAX_DEPTH = 3; // 最大递归深度

    private static final float ZOOM_FACTOR = 0.9f;  // 每次滚动的缩放系数
    private static final double MIN_FOV = Math.toRadians(5);   // 最小视野角度
    private static final double MAX_FOV = Math.toRadians(150); // 最大视野角度

    public static void main(String[] args) {

        System.setProperty("j3d.rend", "javax.media.j3d.SimpleUniverse");
        // 创建虚拟世界
        SimpleUniverse universe = new SimpleUniverse();

        // 创建主场景
        BranchGroup rootGroup = new BranchGroup();

        // 创建变换组（用于鼠标旋转）
        TransformGroup mainTG = new TransformGroup();
        mainTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

        // 定义原始三角形顶点
        Point3f[] originalPoints = {
                new Point3f(0.0f, 0.0f, 1.0f),  // A
                new Point3f(1.0f, 0.0f, 0.0f),  // B
                new Point3f(0.0f, 1.0f, 0.0f)   // C
        };

        // 生成初始细分三角形
        Random rand = new Random();
        generateSmallerTriangles(originalPoints, rand, mainTG, 0);

        // 添加鼠标旋转行为
        MouseRotate mouseRotate = new MouseRotate();
        mouseRotate.setTransformGroup(mainTG);
        mouseRotate.setSchedulingBounds(new BoundingSphere());
        rootGroup.addChild(mouseRotate);

        // 装配场景图
        rootGroup.addChild(mainTG);
        universe.addBranchGraph(rootGroup);

        // 设置窗口
        Canvas3D canvas = createCanvas(universe);
        JFrame frame = createFrame(canvas);

        // 设置观察位置
        universe.getViewingPlatform().setNominalViewingTransform();
    }

    // 递归生成三角形
    private static void generateSmallerTriangles(Point3f[] points, Random rand,
                                                 Node parent, int depth) {
        if (depth >= MAX_DEPTH) return;

        // 创建当前层级的变换组
        TransformGroup tg = new TransformGroup();

        // 生成细分点
        Point3f[] newPoints = new Point3f[points.length * 4];
        int index = 0;

        for (int i = 0; i < points.length; i += 3) {
            Point3f p0 = points[i];
            Point3f p1 = points[i+1];
            Point3f p2 = points[i+2];

            // 计算中点并添加随机偏移
            Point3f m01 = midpoint(p0, p1, rand, depth);
            Point3f m12 = midpoint(p1, p2, rand, depth);
            Point3f m20 = midpoint(p2, p0, rand, depth);

            // 生成四个子三角形
            addTriangle(newPoints, index++, p0, m01, m20);
            addTriangle(newPoints, index++, m01, p1, m12);
            addTriangle(newPoints, index++, m20, m12, p2);
            addTriangle(newPoints, index++, m01, m12, m20);
        }

        // 创建几何体
        TriangleArray geometry = new TriangleArray(newPoints.length, TriangleArray.COORDINATES);
        geometry.setCoordinates(0, newPoints);

        // 创建带颜色的外观
        Appearance app = createAppearance(depth);
        Shape3D shape = new Shape3D(geometry, app);

        // 添加到场景
        tg.addChild(shape);
        ((Group)parent).addChild(tg);

        // 递归生成下一层
        generateSmallerTriangles(newPoints, rand, tg, depth+1);
    }

    // 计算中点并添加随机偏移
    private static Point3f midpoint(Point3f a, Point3f b, Random rand, int depth) {
        float offset = rand.nextFloat() * 2.0f / (depth + 1);
        return new Point3f(
                (a.x + b.x) / 2,
                (a.y + b.y) / 2 + offset,
                (a.z + b.z) / 2
        );
    }

    // 创建颜色外观（根据深度渐变）
    private static Appearance createAppearance(int depth) {
        float ratio = (float)depth / MAX_DEPTH;
        Color3f color = new Color3f(1.0f, 1.0f - ratio, 1.0f - ratio);

        ColoringAttributes ca = new ColoringAttributes(color, ColoringAttributes.SHADE_GOURAUD);
        Appearance app = new Appearance();
        app.setColoringAttributes(ca);
        return app;
    }

    // 添加三角形到数组
    private static void addTriangle(Point3f[] arr, int index,
                                    Point3f a, Point3f b, Point3f c) {
        arr[index*3] = a;
        arr[index*3+1] = b;
        arr[index*3+2] = c;
    }

    // 创建3D画布
    // 创建3D画布（包含滚轮缩放支持）
    private static Canvas3D createCanvas(SimpleUniverse universe) {
        GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration();
        Canvas3D canvas = new Canvas3D(config);
        canvas.setPreferredSize(new Dimension(800, 600));

        // 添加鼠标滚轮缩放监听器
        canvas.addMouseWheelListener(new MouseWheelListener() {
            @Override
            public void mouseWheelMoved(MouseWheelEvent e) {
                View view = universe.getViewer().getView();
                double currentFov = view.getFieldOfView();
                int notches = e.getWheelRotation();

                // 计算新的视野角度
                double newFov = currentFov;
                if (notches < 0) { // 滚轮向上（放大）
                    newFov *= ZOOM_FACTOR;
                } else {           // 滚轮向下（缩小）
                    newFov /= ZOOM_FACTOR;
                }

                // 限制视野范围
                newFov = Math.max(MIN_FOV, Math.min(newFov, MAX_FOV));

                // 应用新视野
                view.setFieldOfView(newFov);
            }
        });

        return canvas;
    }

    // 创建主窗口
    private static JFrame createFrame(Canvas3D canvas) {
        JFrame frame = new JFrame("3D递归三角形 (深度：" + MAX_DEPTH + ")");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(canvas, BorderLayout.CENTER);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        return frame;
    }
}
